#include "renderpseudothread.h"
#include "colorScale.h"

RenderPseudoThread::RenderPseudoThread()
{
    painter=NULL;
    populated=false;
}

RenderPseudoThread::~RenderPseudoThread()
{
    if (painter){
        delete painter;
    }
}

void RenderPseudoThread::render(QSize aSize, QMatrix aMatrix)
{
    stop();

    if (!populated && size==aSize && matrix==aMatrix){  //there is no need to render
        return;
    }
    if (populated){
        populated=false;
    }

    size=aSize;
    matrix=aMatrix;

    // initialize temporary variables for current computation
    if (painter){   // painter is on image, old painter must be destroyed before new image is created
        delete painter;
    }
    image = QImage(size, QImage::Format_ARGB32);
    if (image.isNull()){
        return;
    }
    painter = new QPainter(&image);

    image.fill(qRgba(255,255,255,0));   //fill background with transparent white color
    painter->setWorldMatrix(matrix);

    it=triangles.begin();

    start();    //start pseudo thread
}

void RenderPseudoThread::populate(QVector<triangle *> aTriangles, const QVector<float> &aVertexHeight, const QVector<QPointF> &aVertices, float aMin, float aMax)
{
    stop();
    min=aMin;
    max=aMax;
    triangles=aTriangles;
    vertexHeight=aVertexHeight;
    vertices=aVertices;
    populated=true;
}

bool RenderPseudoThread::loopStep()
{
    //this loop is divided into single steps
    //for (QVector<triangle*>::iterator it=triangles.begin(); it!=triangles.end(); it++){
    QPointF v1=vertices[(*it)->get1()-1];
    QPointF v2=vertices[(*it)->get2()-1];
    QPointF v3=vertices[(*it)->get3()-1];

    float h1( vertexHeight[(*it)->get1()-1]);
    float h2( vertexHeight[(*it)->get2()-1]);
    float h3( vertexHeight[(*it)->get3()-1]);
    Vector3D vect1(v1,h1), vect2(v2,h2), vect3(v3,h3);
    QPolygonF pol;
    pol << matrix.map(v1) << matrix.map(v2) << matrix.map(v3);
    if (image.rect().intersects( pol.boundingRect().toRect() ) ){
        drawTriangle(vect1,vect2,vect3);
    }
    it++;
    //}

    if (it==triangles.end()){
        painter->end();
        emit workDone(image);
        return true;
    } else {
        return false;
    }
}

void RenderPseudoThread::drawTriangle(const Vector3D& v1, const Vector3D& v2, const Vector3D& v3){

    painter->setWorldMatrixEnabled(false);
    QMatrix transMatrix = painter->matrix();

    // get values of x and y after transformation in context of no transform
    Vector3D p1=Vector3D(transMatrix.map(v1), v1.z());
    Vector3D p2=Vector3D(transMatrix.map(v2), v2.z());
    Vector3D p3=Vector3D(transMatrix.map(v3), v3.z());

    QMultiMap <float,Vector3D> yMap;  //using QMultiMap to sort vertices  p1, p2, p3 according it's y-value
    yMap.insert(p1.y(), p1);
    yMap.insert(p2.y(), p2);
    yMap.insert(p3.y(), p3);

    QMultiMap <float,Vector3D>::iterator it=yMap.begin();
    p1=it.value();
    int x1=round(p1.x());
    int y1=round(p1.y());
    it++;
    p2=it.value();
    int x2=round(p2.x());
    int y2=round(p2.y());
    it++;
    p3=it.value();
    int y3=round(p3.y());
    int x3=round(p3.x());

    int a=x2-x1;
    int b=x3-x1;
    int c=y2-y1;
    int d=y3-y1;
    int e=x3-x2;
    float z1=p1.z();
    float z2=p2.z();
    float z3=p3.z();
    float h1, h2;
    int j1, j2;
    int denom=(y3-y2);
    QLinearGradient gradient;//(j1,i,j2,i);
    QPen pen;
    colorScale cs(min,max);
    //optimalization: don't compute the same thing several times
    float exp1=0;
    float exp2=0;
    if (c){
        exp1=(float)a/c;
        exp2=(z2-z1)/c;
    }
    float exp3=0;
    float exp4=0;
    if (d) {
        exp3=(float) b/d;
        exp4=(z3-z1)/d;
    }
    float exp5=0;
    float exp6=0;
    if (denom){
        exp5=(float) e/denom;
        exp6=(z3-z2)/denom;
    }
    for (int i=y1; i<y2; ++i){
        j1=x2+(i-y2)*exp1;
        h1=z1+(i-y1)*exp2;

        j2=x3+(i-y3)*exp3;
        h2=z1+(i-y1)*exp4;

        gradient.setStart(j1,i);
        gradient.setFinalStop(j2,i);
        gradient.setColorAt(0,cs.getColor(h1));
        gradient.setColorAt(1,cs.getColor(h2));
        painter->setPen(QPen(gradient,0));
        painter->drawLine(j1,i,j2,i);
    }

    for (int i=y2; i<y3; ++i){
        j1=x2+(i-y2)*exp5;
        h1=z2+(i-y2)*exp6;

        j2=x1+(i-y1)*exp3;
        h2=z1+(i-y1)*exp4;

        gradient.setStart(j1,i);
        gradient.setFinalStop(j2,i);
        gradient.setColorAt(0,cs.getColor(h1));
        gradient.setColorAt(1,cs.getColor(h2));
        pen.setBrush(gradient);
        painter->setPen(pen);
        painter->drawLine(j1,i,j2,i);
    }

    painter->setPen(Qt::black);
    painter->setWorldMatrixEnabled(true);
}

